home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 2.toast / pc / sample code / printing / rotated thingies / Éusing text piccomments / rotn text.p < prev    next >
Encoding:
Text File  |  2000-09-28  |  12.2 KB  |  485 lines

  1. {
  2.     File:        Rotn Text.p
  3.  
  4.     Contains:    Rotn Text demonstrates how to rotate text on PostScript printers
  5.                 using the TextBegin/End PicComments.  PrGeneral is used to change
  6.                 the resolution, which throws another wrench in the works; you have
  7.                 to scale everything.
  8.  
  9.     Written by: Dave Hersey    
  10.  
  11.     Copyright:    Copyright © 1991-1999 by Apple Computer, Inc., All Rights Reserved.
  12.  
  13.                 You may incorporate this Apple sample source code into your program(s) without
  14.                 restriction. This Apple sample source code has been provided "AS IS" and the
  15.                 responsibility for its operation is yours. You are not permitted to redistribute
  16.                 this Apple sample source code as "Apple sample source code" after having made
  17.                 changes. If you're going to re-distribute the source, we require that you make
  18.                 it clear in the source that the code was descended from Apple sample source
  19.                 code, but that you've made changes.
  20.  
  21.     Change History (most recent first):
  22.                 7/26/1999    Karl Groethe    Updated for Metrowerks Codewarror Pro 2.1
  23.                 
  24.  
  25. }
  26.  
  27. PROGRAM RotnText;
  28.  
  29. USES
  30.     Memory, QuickDraw, ToolUtils, Traps, Printing, Packages,Devices,Fonts;
  31.  
  32. CONST
  33.  
  34.     {The following constants are used to identify menus and their items. The menu IDs
  35.      have an "m" prefix and the item numbers within each menu have an "i" prefix.}
  36.  
  37.     rMenuBar    = 128;                    {menubar}
  38.  
  39.     mApple        = 128;                    {Apple menu}
  40.     iAbout        = 1;
  41.  
  42.     mFile        = 129;                    {File menu}
  43.     iPrint        = 1;
  44.     iQuit        = 3;
  45.  
  46.     mEdit        = 130;                    {Edit menu}
  47.  
  48.  
  49. VAR
  50.  
  51.     gQuitting    : Boolean;                {"Are we all done?" flag}
  52.  
  53.  
  54. {*------ RotateText -----------------------------------------------------------------*}
  55.  
  56. {**
  57.  **      RotateText draws the passed text rotated 45° using the TextBegin/End
  58.  **      comments.  The center of rotation and start of text drawing is done
  59.  **      at the "where" point passed.
  60.  **}
  61.  
  62. {$S Main}
  63. PROCEDURE RotateText(theText : Str255; where : Point);
  64.  
  65.     CONST
  66.         TextBegin    = 150;
  67.         TextEnd        = 151;
  68.         TextCenter    = 154;
  69.  
  70.     TYPE
  71.         TTxtCenterHdl    = ^TTxtCenterPtr;
  72.         TTxtCenterPtr    = ^TTxtCenterRec;
  73.         TTxtCenterRec    = RECORD
  74.                             y, x: Fixed;    {offset from current pen location to center of rotation.}
  75.                           END;     { TTxtCenterRec }
  76.  
  77.         TTxtPicHdl        = ^TTxtPicPtr;
  78.         TTxtPicPtr        = ^TTxtPicRec;
  79.         TTxtPicRec        = PACKED RECORD
  80.                             tJus: Byte;        {0,1,2,3,4 -> none, left, center, right, full justification.}
  81.                             tFlip: Byte;    {0,1,2 -> none, horizontal, vertical coordinate flip.}
  82.                             tRot: integer;    {0..360 -> clockwise rotation in degrees.}
  83.                             tLine: Byte;    {1,2,3.. -> single, 1 1/2, double.. spacing}
  84.                             tCmnt: Byte;    {Reserved.}
  85.                           END;     { TTxtPicRec }
  86.  
  87.     VAR
  88.         txtHdl        : TTxtPicHdl;
  89.         txtCtr        : TTxtCenterHdl;
  90.  
  91.     BEGIN
  92.  
  93.     {Do a dummy draw to set the clipping region.}
  94.  
  95.         PenSize(0, 0);
  96.         MoveTo(0, 0);
  97.         LineTo(0, 0);
  98.         PenSize(1, 1);
  99.  
  100.         txtCtr := TTxtCenterHdl(NewHandle(SizeOf(TTxtCenterRec)));
  101.         txtCtr^^.y := 0; {no y offset to center of rotation}
  102.         txtCtr^^.x := 0; {no x offset to center of rotation}
  103.  
  104.         txtHdl := TTxtPicHdl(NewHandle(SizeOf(TTxtPicRec)));
  105.         txtHdl^^.tJus := 0;     {no justification}
  106.         txtHdl^^.tFlip := 0; {no flip}
  107.         txtHdl^^.tRot := 45; {45° rotation}
  108.         txtHdl^^.tLine := 1; {single spacing}
  109.  
  110.     {Begin text rotation.}
  111.  
  112.         PicComment(TextBegin,GetHandleSize(handle(txtHdl)),handle(txtHdl));
  113.  
  114.     {Set the center of rotation and draw.}
  115.  
  116.         MoveTo(where.h, where.v);
  117.         PicComment(TextCenter,GetHandleSize(handle(txtCtr)),handle(txtCtr));
  118.  
  119.         DrawString(theText);
  120.  
  121.     {Text rotation ends here.}
  122.  
  123.         PicComment(TextEnd,0,NIL);
  124.         DisposeHandle(handle(txtHdl)); {Clean up}
  125.         DisposeHandle(handle(txtCtr));
  126.  
  127.     END;    {**  RotateText  **}
  128.  
  129.  
  130. {*------ DrawStuff -----------------------------------------------------------------*}
  131.  
  132. {**
  133.  **      DrawStuff draws the objects.  prRsl is the resolution of the printer's
  134.  **        GrafPort and is used to determine the amount to scale everything.
  135.  **}
  136.  
  137. {$S Main}
  138.  PROCEDURE DrawStuff(theGPort : GrafPtr; prRsl : Integer);
  139.  
  140.  VAR
  141.     oldPort        : GrafPtr;
  142.     fNum        : Integer;
  143.     scalar        : Real;
  144.     where        : Point;
  145.  
  146.  BEGIN
  147.  
  148. {Get the current port and save it.}
  149.     
  150.     GetPort(oldPort);
  151.     SetPort(theGPort);
  152.  
  153.     scalar := prRsl;
  154.     scalar := scalar / 72;
  155.  
  156.     GetFNum('Times', fNum);
  157.     TextFont(fNum);
  158.     TextSize(Round(24 * scalar));
  159.  
  160.     where.h := Round(50 * scalar);
  161.     where.v := Round(50 * scalar);
  162.     RotateText('This is a line of rotated text.', where);
  163.  
  164.     SetPort(oldPort);
  165.  
  166.  END;    {**  DrawStuff  **}
  167.  
  168.  
  169. {*------ GetBestRsl -----------------------------------------------------------------*}
  170.  
  171. {**
  172.  **      GetBestRsl determines the best "square" resolution supported by the printer.
  173.  **        For example, 300 dpi horizontal by 300 dpi vertical.  It isn't necessary to
  174.  **        use square resolutions, but it generally proves easier.  We use PrGeneral and
  175.  **        the getRslDataOp opCode to get a list of the supported resolutions for our
  176.  **        printer.  Then we just go through the rgRslRec and find the maximum square
  177.  **        resolution for discrete or non-discrete data, whichever we have.  Finally, we
  178.  **        make sure it's divisible by 72 for cleaner scaling.
  179.  **}
  180.  
  181. {$S Main}
  182. FUNCTION GetBestRsl :Integer;
  183.  
  184. VAR
  185.         err            : OSErr;
  186.         theRes, num    : Integer;
  187.         getRslData    : TGetRslBlk;
  188.  
  189. BEGIN
  190.  
  191. {Start off with our maximum resolution at 0, then call PrGeneral and parse our list
  192.  of returned values.}
  193.  
  194.         theRes := 0;
  195.         getRslData.iOpCode := getRslDataOp;
  196.  
  197.         PrGeneral(@getRslData);
  198.         err := getRslData.iError;
  199.  
  200. {If our printer only supports discrete resolutions, find the largest square one and
  201.  use that.  If our printer supports a range of resolutions, choose the smaller of the
  202.  maximum X and Y resolutions, then make it divisible by 72 for cleaner scaling.}
  203.  
  204.         IF (err = noErr) THEN
  205.             IF (getRslData.XRslRg.iMax = 0) AND (getRslData.YRslRg.iMax = 0) THEN
  206.                 BEGIN                                                                {Discrete resolutions.}
  207.                     FOR num := 1 TO getRslData.iRslRecCnt DO
  208.                         IF (getRslData.rgRslRec[num].iXRsl = getRslData.rgRslRec[num].iYRsl)
  209.                             AND (theRes < getRslData.rgRslRec[num].iXRsl) THEN
  210.                                 theRes := getRslData.rgRslRec[num].iXRsl;
  211.                 END
  212.             ELSE
  213.                 BEGIN                                                                {Variable resolutions.}
  214.                     IF (getRslData.XRslRg.iMax < getRslData.YRslRg.iMax) THEN
  215.                         theRes := (getRslData.XRslRg.iMax DIV 72) * 72            {Use multiple of 72 closest to max. X resolution.}
  216.                     ELSE
  217.                         theRes := (getRslData.YRslRg.iMax DIV 72) * 72            {Use multiple of 72 closest to max. Y resolution.}
  218.                 END;
  219.             
  220.  
  221. {In the unlikely event that PrGeneral fails and theRes is still 0, set it to 72.
  222.  This most likely is a supported resolution.  Finally return the best resolution we
  223.  could find.}
  224.  
  225.         IF theRes = 0 THEN theRes := 72;
  226.         GetBestRsl := theRes;
  227.  
  228. END;    {**  GetBestRsl  **}
  229.  
  230.  
  231. {*------ PrintStuff ----------------------------------------------------------------*}
  232. {**
  233.  **        PrintStuff will call all of the necessary Print Manager calls to print 
  234.  **        a document. It checks PrError after each Print Manager call. If an error 
  235.  **     is found, all of the Print Manager open calls (i.e. PrOpen, PrOpenDoc...) 
  236.  **        will have a corresponding close call before the error is posted to the user. 
  237.  **        You want to use this approach to make sure the Print Manager closes properly 
  238.  **        and all temporary memory is released.
  239.  **}
  240.  
  241. {$S Main}
  242. PROCEDURE PrintStuff;
  243.  
  244. VAR
  245.  
  246.     oldPort          : GrafPtr;
  247.     thePrRecHdl        : THPrint;
  248.     thePrPort        : TPPrPort;
  249.     theStatus        : TPrStatus;
  250.     rslData            : TSetRslBlk;
  251.     err                : OSErr;
  252.     prRsl            : Integer;
  253.     bestRsl            : Integer;
  254.  
  255. BEGIN
  256.  
  257.  
  258. {Get our current port and create a print handle.  If no errors,
  259.  do our PrOpen call and, if no errors again, get the default
  260.  settings for the current driver.}
  261.  
  262.     GetPort(oldPort);
  263.     thePrRecHdl := THPrint(NewHandle(sizeof(TPrint)));
  264.     
  265.     IF (MemError = noErr) THEN
  266.     BEGIN
  267.         PrOpen;
  268.         IF (PrError = noErr) THEN
  269.         BEGIN
  270.             PrintDefault(thePrRecHdl);
  271.  
  272.             bestRsl := GetBestRsl;
  273.             rslData.iOpCode := SetRslOp;
  274.             rslData.hPrint := thePrRecHdl;
  275.             rslData.iXRsl := bestRsl;
  276.             rslData.iYRsl := bestRsl;
  277.             PrGeneral(@rslData);
  278.             err := rslData.iError;
  279.     
  280.             prRsl := bestRsl;
  281.  
  282.  
  283. {If we still have no errors, give style and print job dialogs, then open a
  284.  document and its page.  Keep checking for those dang printer errors.}
  285.  
  286.             IF (PrError = noErr) THEN
  287.             BEGIN
  288.                 IF (PrStlDialog(thePrRecHdl)) THEN
  289.                 BEGIN
  290.                     IF (PrJobDialog(thePrRecHdl)) THEN 
  291.                     BEGIN
  292.                         thePrPort := PrOpenDoc(thePrRecHdl, NIL, NIL);
  293.                                
  294.                         IF (PrError = noErr) THEN
  295.                         BEGIN
  296.                             PrOpenPage(thePrPort, NIL);
  297.  
  298.  
  299. {If we're still running error-free, draw our test page.  prRsl is the
  300.  resolution of our printer port.}
  301.  
  302.                             IF (PrError = noErr) THEN
  303.                                 DrawStuff(GrafPtr(thePrPort), prRsl);
  304.  
  305.  
  306. {When done, close our page and document and spool the document if necessary.  When
  307.  finshed, call PrClose to end the whole shabang.}
  308.  
  309.                             PrClosePage(thePrPort);
  310.                         END;
  311.                              
  312.                         PrCloseDoc(thePrPort);
  313.                              
  314.                         IF (thePrRecHdl^^.prJob.bJDocLoop = bSpoolLoop) and (PrError = noErr) THEN
  315.                             PrPicFile(thePrRecHdl, NIL, NIL, NIL, @theStatus);
  316.                     END;
  317.                 END;
  318.             END;
  319.         END;
  320.         
  321.         PrClose;
  322.  
  323.     END;
  324.  
  325. END;    {**  PrintStuff  **}
  326.  
  327.  
  328. {*------ Initialize ----------------------------------------------------------------*}
  329. {**
  330.  **        Initialize just handles necessary Toolbox initializing, setting our quitting 
  331.  **        flag to FALSE and installing our menus.
  332.  **}
  333.  
  334. {$S Initialize}
  335. PROCEDURE Initialize;
  336.  
  337. VAR
  338.     menuBar    : Handle;
  339.     
  340. BEGIN
  341.  
  342.     InitGraf(@qd.thePort);
  343.     InitFonts;
  344.     InitWindows;
  345.     InitMenus;
  346.     TEInit;
  347.     InitDialogs(NIL);
  348.     InitCursor;
  349.     FlushEvents(everyEvent, 0);    
  350.  
  351.     gQuitting := FALSE;
  352.  
  353.     menuBar := GetNewMBar(rMenuBar);        {read menus into menu bar}
  354.     IF (menuBar = NIL) THEN ExitToShell;    {should do real error stuff here.}
  355.     SetMenuBar(menuBar);                    {install menus}
  356.     DisposeHandle(menuBar);
  357.     AppendResMenu(GetMenuHandle(mApple), 'DRVR');    {add DA names to Apple menu}
  358.     DrawMenuBar;
  359.  
  360. END;    {**  Initialize  **}
  361.  
  362.  
  363. {$S _DataInit}
  364. PROCEDURE _DataInit; EXTERNAL;
  365.  
  366. {This routine is automatically linked in by the MPW Linker. This external
  367.  reference to it is done so that we can unload its segment, %A5Init.}
  368.  
  369.  
  370.  
  371. {*------ DoMenuCommand ----------------------------------------------------------------*}
  372. {**
  373.  **        DoMenuCommand is called when an item is chosen from the menu bar (after calling 
  374.  **        MenuSelect or MenuKey).  It does the right thing for each command.
  375.  **}
  376.  
  377. {$S Main}
  378. PROCEDURE DoMenuCommand(menuResult: LONGINT);
  379.  
  380. VAR
  381.     menuID, menuItem    : INTEGER;
  382.     daRefNum            : INTEGER;
  383.     daName                : Str255;
  384.  
  385. BEGIN
  386.  
  387. {Get the menu ID and item ID.}
  388.  
  389.     menuID := HiWrd(menuResult);
  390.     menuItem := LoWrd(menuResult);
  391.  
  392.     CASE menuID OF
  393.         mApple:
  394.             CASE menuItem OF
  395.                 iAbout:                {bring up alert for About}
  396.                     (* We do nothing here... *);
  397.  
  398.                 OTHERWISE
  399.                 BEGIN        {all non-About items in this menu are DAs}
  400.                     GetMenuItemText(GetMenuHandle(mApple), menuItem, daName);
  401.                     daRefNum := OpenDeskAcc(daName);
  402.                 END;
  403.             END;
  404.  
  405.         mFile:                            {File Menu}
  406.             CASE menuItem OF
  407.                 iPrint:                        {-> Print Test Page.}
  408.                     PrintStuff;
  409.                 iQuit:
  410.                     gQuitting := TRUE;        {-> Quit}
  411.             END;
  412.     END;        
  413.  
  414.     HiliteMenu(0);
  415.  
  416. END;    {**  DoMenuCommand  **}
  417.  
  418.  
  419. {*------ DoEvent ----------------------------------------------------------------*}
  420. {**
  421.  **        DoEvent handles incoming events for our app.  In this skimpy sample, we
  422.  **        only handle menu events and system clicks.
  423.  **}
  424.  
  425. {$S Main}
  426. PROCEDURE DoEvent;
  427.  
  428. VAR
  429.     part        : INTEGER;
  430.     key            : Char;
  431.     event        : EventRecord;
  432.     window        : WindowPtr;
  433.  
  434. BEGIN
  435.  
  436. {Repeatedly handle menu selecting events until our quit flag is set.}
  437.  
  438.     REPEAT
  439.         BEGIN
  440.             SystemTask;                                    {This must be called if using GetNextEvent}
  441.  
  442.             IF (GetNextEvent(everyEvent, event)) THEN
  443.                 CASE event.what OF
  444.                     mouseDown:
  445.                         BEGIN
  446.                             part := FindWindow(event.where, window);
  447.                             CASE part OF
  448.                                 inMenuBar:
  449.                                     DoMenuCommand(MenuSelect(event.where));
  450.                 
  451.                                 inSysWindow:
  452.                                     SystemClick(event, window);
  453.                             END;
  454.                         END;
  455.     
  456.                     keyDown, autoKey:
  457.                         BEGIN
  458.                             key := CHR(BAnd(event.message, charCodeMask));
  459.                             IF (BAnd(event.modifiers, cmdKey) <> 0) AND (event.what = keyDown) THEN
  460.                                 DoMenuCommand(MenuKey(key));
  461.                         END;
  462.                 END;
  463.         END;
  464.     UNTIL gQuitting;
  465.  
  466. END;    {**  DoEvent  **}
  467.  
  468.  
  469. {*------ Main ----------------------------------------------------------------*}
  470. {**
  471.  **        Main kickstarts our app.
  472.  **}
  473.  
  474. {$S Main}
  475. BEGIN
  476.  
  477.     //UnloadSeg(@_DataInit);    {note that _DataInit must not be in Main!}
  478.     MaxApplZone;            {expand the heap so code segments load at the top}
  479.     Initialize;                {initialize the program}
  480.     //UnloadSeg(@Initialize);    {note that Initialize must not be in Main!}
  481.     DoEvent;                {handle menu events until quitting.}
  482.  
  483. END.    {**  Rotn Text.  **}
  484.  
  485.